#include"Shader.h"
using namespace std;

void PhongShader::VS(Vertex& v0, Vertex& v1, Vertex& v2)
{
	vert.v0 = v0;
	vert.v1 = v1;
	vert.v2 = v2;


	Vertex* v = &v0;

	for (int i = 0; i < 3; i++) {
		switch (i)
		{
		case 0:
			v = &v0;
			vert.p0 = v0.pos;
			vert.p0 = vert.m.MultiplyVec4(vert.p0);
			vert.p0 = vert.lightVertical.MultiplyVec4(vert.p0);
			vert.p0 = vert.lightParallel.MultiplyVec4(vert.p0);
			break;
		case 1:
			v = &v1;
			vert.p1 = v1.pos;
			vert.p1 = vert.m.MultiplyVec4(vert.p1);
			vert.p1 = vert.lightVertical.MultiplyVec4(vert.p1);
			vert.p1 = vert.lightParallel.MultiplyVec4(vert.p1);
			break;
		case 2:
			v = &v2;
			vert.p2 = v2.pos;
			vert.p2 = vert.m.MultiplyVec4(vert.p2);
			vert.p2 = vert.lightVertical.MultiplyVec4(vert.p2);
			vert.p2 = vert.lightParallel.MultiplyVec4(vert.p2);
			break;
		
		}

		v->pos = vert.m.MultiplyVec4(v->pos);

		Matrix normmat = vert.m;

		normmat.mat[0][3] = 0;
		normmat.mat[1][3] = 0;
		normmat.mat[2][3] = 0;

		v->normal = normmat.MultiplyVec4(v->normal).Normalize();

		float diffuse = 0.0, specular = 0.0, ambient = 0.1f;

		for (auto light : vert.dirLights) {
			Vec4f ldir = light.GetDir().Normalize();
			diffuse += std::fmax(0.0f, ldir.Dot(v->normal)) * light.intensity;

			Vec4f h = ((vert.camPos - v->pos).Normalize() + ldir).Normalize();
			specular += std::pow(std::fmax(0.0f, v->normal.Dot(h)), 1) * light.intensity;
		}


		v->color = v->color * std::fmin(1.0f, specular + diffuse + ambient);
		v->pos = vert.v.MultiplyVec4(v->pos);
		v->pos = vert.p.MultiplyVec4(v->pos);
		v->pos.standard();

	}
	if (v1.pos.y < v0.pos.y) {
		std::swap(vert.p0, vert.p1);
		std::swap(v1, v0);
	}
	if (v2.pos.y < v0.pos.y) {
		std::swap(vert.p0, vert.p2);
		std::swap(v2, v0);
	}
	if (v2.pos.y < v1.pos.y) {
		std::swap(vert.p1, vert.p2);
		std::swap(v2, v1);
	}


}

bool PhongShader::FS(Vertex& v, Vec4f g)
{
	v.color = v.color * frag.baseTexture->Sample(v.uv.x, v.uv.y);
	Vec4f norm = vert.v0.normal * g.x + vert.v1.normal * g.y + vert.v2.normal * g.z;
	Vec4f posLightSpace = vert.p0 * g.x + vert.p1 * g.y + vert.p2 * g.z;

	float bias = 0.005;
	if (vert.dirLights.size() > 0) {
		bias = std::fmax(0.02f * (1.0f - std::fabs(Vec4f::Dot(norm.Normalize(), vert.dirLights[0].GetDir().Normalize()))), 0.005);
	}

	float depth = CalcShadow(posLightSpace, bias);
	v.color = v.color * (1 - depth);
	return v.color.a > 0;
}

float PhongShader::CalcShadow(Vec4f& lightSpace, double bias)
{
	float invW = 1.0f / lightSpace.w;

	lightSpace.x = (lightSpace.x * invW + 1.0f) * 0.5f * (frag.depthBuffer->width - 1) + 0.5;
	lightSpace.y = (lightSpace.y * invW + 1.0f) * 0.5f * (frag.depthBuffer->height - 1) + 0.5;

	float depth = (lightSpace.z + 1.0f) / 2.0f;

	float shadow = 0.0f;
	float closestDepth = frag.depthBuffer->Sample(lightSpace.y, lightSpace.x);
	shadow = depth - bias > closestDepth ? 1 : 0;

	return shadow;
}

void ShadowShader::VS(Vertex& v0, Vertex& v1, Vertex& v2)
{
	Vertex* v = &v1;
	for (int i = 0; i < 3; i++) {
		switch (i)
		{
		case 0: v = &v0; break;
		case 1:v = &v1; break;
		case 2:v = &v2; break;

		}
		v->pos = vert.m.MultiplyVec4(v->pos);
		v->pos = vert.lightVertical.MultiplyVec4(v->pos);
		v->pos = vert.lightParallel.MultiplyVec4(v->pos);
		v->pos.standard();
	}

	if (v1.pos.y < v0.pos.y) {
		std::swap(v1, v0);
	}
	if (v2.pos.y < v0.pos.y) {
		std::swap(v2, v0);
	}
	if (v2.pos.y < v1.pos.y) {
		std::swap(v2, v1);
	}
	

}

bool ShadowShader::FS(Vertex& v, Vec4f g)
{
	return false;
}




